<?php

namespace app\admin\controller;

use app\admin\traits\EndAuthTrait;
use app\BaseController;
use app\common\exception\ApiErrDesc;
use app\common\exception\ApiException;
use app\common\service\auth\JwtService;
use think\App;
use think\facade\Db;


/**
 * 后台控制器基类
 * Class EndController
 * @package app\admin\controller
 * @author ^2_3^王尔贝
 */
class EndController extends BaseController
{
    use EndAuthTrait;

    /**
     * 应用模块名称
     * @var string
     */
    protected $appName;

    /**
     * 控制器名称
     * @var string
     */
    protected $controllerName;

    /**
     * 操作方法名称
     * @var string
     */
    protected $methodName;

    /**
     * 是否超管
     * @var bool
     */
    protected $isSuperAdmin = false;

    /**
     * 管理人员信息
     * @var array
     */
    protected $admin = [
        'info' => [],
        'roleIds' => [],
    ];

    /**
     * 不用检测token
     * @var array
     */
    protected $notCheck = [];

    /**
     * 不用检测action
     * @var array
     * @author ^2_3^王尔贝
     */
    protected $notCheckAction = [];

    /**
     * jwt令牌
     * @var JwtService
     * @author ^2_3^王尔贝
     */
    protected $jwtService;

    public function __construct(App $app)
    {
        parent::__construct($app);

        $this->jwtService = JwtService::getInstance();

        //// check the token
        $this->tokenCheck();
    }

    /**
     * 转换分页数据
     * @param array $arraySet
     * @return array
     * @author ^2_3^王尔贝
     */
    protected function transformPage($arraySet = [])
    {
        if( empty( $arraySet ) ) {
            return [];
        }

        $arraySet['pageSize'] = $arraySet['per_page'];
        $arraySet['pageNo'] = $arraySet['current_page'];
        $arraySet['totalCount'] = $arraySet['total'];
        $arraySet['totalPage'] = ceil( $arraySet['totalCount'] / $arraySet['pageSize'] );

        return $arraySet;
    }

    /**
     * 令牌解析
     * @throws ApiException
     * @author ^2_3^王尔贝
     */
    private function tokenCheck()
    {
        //// 应用/控制器/操作方法 解析
        $rule = $this->request->rule()->getRoute();
        preg_match_all('/app\\\(\w+)\\\controller\\\(\w+)@(\w+)/', $rule, $ruleMatches);
        if( count( $ruleMatches ) != 4 ) {
            throw new ApiException(ApiErrDesc::END_RULE_PARSE);
        }
        $this->appName = app('http')->getName();
        $this->controllerName = $ruleMatches['2'][0];
        $this->methodName = $ruleMatches['3'][0];

        //// 权限验证
        if ( !in_array($this->methodName, $this->notCheck)) {
            //// 获取token
            $header = $this->request->header();
            if( empty( $header ) || empty( $header['access-token'] ) ) {
                throw new ApiException(ApiErrDesc::ERR_NO_TOKEN);
            }

            //// 解析token
            $accessToken = $header['access-token'];
            $jwtObj = $this->jwtService->verifyToken( $accessToken );
            $jwtArr = (array)$jwtObj->decodeToken;
            $adminId = $jwtArr['id'];
            $this->admin['token'] = $accessToken;

            //// admin info
            $admin = Db::name('admin')->where(['id' => $adminId])->find();
            if($admin['status'] != 1){
                throw new ApiException(ApiErrDesc::END_ACCOUNT_DISABLED);

            }else {
                $this->admin['info'] = $admin;

                $adminRoles = Db::name('admin_role')
                    ->where(['admin_id' => $adminId])
                    ->column('role_id');
                $this->admin['roleIds'] = $adminRoles;
            }
            // 检测权限
            if (!in_array($this->methodName, $this->notCheckAction) && !$this->checkAccess($adminId)) {
                throw new ApiException(ApiErrDesc::END_NO_AUTH);
            }
        }
    }

    /**
     * 检测权限
     * @param int $adminId
     * @return bool
     * @throws ApiException
     * @author cenyebao^2_3^
     * @email 1142733640@qq.com
     */
    private function checkAccess($adminId = 0)
    {
        // 如果超级管理员角色，则无需判断
        if (!empty( $this->admin['roleIds'] ) && in_array(1, $this->admin['roleIds'])) {
            $this->isSuperAdmin = true;
            return true;
        }

        $module     = $this->appName;
        $controller = $this->controllerName;
        $action     = $this->methodName;
        $rule       = $module .'/'. $controller .'/'. $action;

        if (!in_array($action, $this->notCheck)) {
            return $this->authCheck($rule, $adminId);

        } else {
            return true;
        }

    }
}